package com.common.util.utils;

import android.os.Environment;
import android.os.StatFs;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.util.List;

public class DiskUtils {

  public static void createNecessaryFolders(String path) {
    int index = path.lastIndexOf("/");
    if (index > 0) {
      String folders = path.substring(0, index);
      File file = new File(folders);
      file.mkdirs();
    }
  }

  public static boolean moveFile(String srcPath, String dstPath) {
    File file = new File(srcPath);
    if (!file.exists()) {
      return false;
    }

    createNecessaryFolders(dstPath);

    File newFile = new File(dstPath);
    if (newFile.exists()) {
      newFile.delete();
    }

    return file.renameTo(newFile);
  }

  public static boolean copyFile(String srcPath, String dstPath) {
    if(dstPath == null) {
      return false;
    }
    File file = new File(srcPath);
    if (!file.exists()) {
      return false;
    }

    createNecessaryFolders(dstPath);

    File newFile = new File(dstPath);
    if (newFile.exists()) {
      newFile.delete();
    }

    try {
      InputStream in = new FileInputStream(file);
      OutputStream out = new FileOutputStream(newFile);

      byte[] buf = new byte[1024];
      int len;
      while ((len = in.read(buf)) > 0) {
        out.write(buf, 0, len);
      }
      in.close();
      out.close();
      return true;
    } catch (FileNotFoundException e) {
      return false;
    } catch (IOException e) {
      return false;
    }
  }

  /**
   * Deletes a file.
   */
  public static void deleteFile(String filePath) {
    if (filePath == null) {
      return;
    }

    final File file = new File(filePath);
    if (!file.exists()) {
      return;
    }
    File temp = null;
    temp = new File(filePath);

    if (temp.isFile()) {
      temp.delete();
    }
  }

  /**
   * Deletes a folder.
   */
  public static void deleteFolder(String folderPath) {
    try {
      deleteFolderFiles(folderPath);
      String filePath = folderPath;
      filePath = filePath.toString();
      final File myFilePath = new File(filePath);
      myFilePath.delete();
    } catch (final Exception e) {
    }
  }

  /**
   * Deletes all files in the specified folder.
   */
  public static void deleteFolderFiles(String folderPath) {
    if (folderPath == null) {
      return;
    }

    final File file = new File(folderPath);
    if (!file.exists()) {
      return;
    }
    if (!file.isDirectory()) {
      return;
    }
    final String[] tempList = file.list();
    File temp = null;
    for (int i = 0; i < tempList.length; i++) {
      if (folderPath.endsWith(File.separator)) {
        temp = new File(folderPath + tempList[i]);
      } else {
        temp = new File(folderPath + File.separator + tempList[i]);
      }

      if (temp.isFile()) {
        temp.delete();
      }

      if (temp.isDirectory()) {
        deleteFolderFiles(folderPath + "/" + tempList[i]);
        deleteFolder(folderPath + "/" + tempList[i]);
      }
    }
  }

  /**
   * file exists.
   */
  public static boolean isExists(String strPath) {
    if (strPath == null) {
      return false;
    }

    final File strFile = new File(strPath);

    if (strFile.exists()) {
      return true;
    }
    return false;

  }

  private static String tag = DiskUtils.class.getSimpleName();
  public static String loadTextAndClose(InputStream in, String encoding) {
    if (in == null) {
      return null;
    }
    try {
      try {
        Reader r = new InputStreamReader(in, encoding == null ? "utf-8"
                : encoding);
        StringBuilder out = new StringBuilder();
        char[] buf = new char[1024];
        int c;
        while ((c = r.read(buf)) >= 0) {
          out.append(buf, 0, c);
        }
        return out.toString();
      } finally {
        in.close();
      }
    } catch (IOException e) {
      return null;
    }
  }

  /**
   * Closes 'closeable', ignoring any checked exceptions. Does nothing if
   * 'closeable' is null.
   */
  public static void closeQuietly(Closeable closeable) {
    if (closeable != null) {
      try {
        closeable.close();
      } catch (final RuntimeException rethrown) {
        throw rethrown;
      } catch (final Exception ignored) {
      }
    }
  }

  public static void deleteRecursively(File dir) throws IOException {
    if (dir.isDirectory()) {
      for (final File file : dir.listFiles()) {
        deleteRecursively(file);
      }
    }
    if (!dir.delete()) {
      throw new IOException("failed to delete file: " + dir);
    }
  }

  public static void deleteIfExists(File file) throws IOException {
    if (file.exists() && !file.delete()) {
      throw new IOException();
    }
  }

  public static byte[] loadBytesAndClose(InputStream in) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
      byte[] buf = new byte[1024];
      int c;
      while ((c = in.read(buf)) >= 0) {
        out.write(buf, 0, c);
      }
    } finally {
      in.close();
    }
    return out.toByteArray();
  }

  public static boolean moveFile(File src, File dst) throws IOException {
    copyFile(src, dst);
    src.delete();
    return true;
  }

  public static boolean copyFile(File src, File dst) throws IOException {
    copyFile2(src, dst);
    return true;
  }

  public static void copyFile2(File src, File dst) throws IOException {
    if(src != null && dst != null) {
      if(!src.exists()) {
        throw new IOException("copy from a file which is not exists:" + src);
      } else {
        if(dst.exists()) {
          dst.delete();
        } else {
          File file = dst.getParentFile();
          if(file != null && !file.exists()) {
            file.mkdirs();
          }
        }

        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;

        try {
          inputStream = new FileInputStream(src);
          outputStream = new FileOutputStream(dst);
          IOUtils.copyAllBytes(inputStream, outputStream);
        } finally {
          IOUtils.safeClose(inputStream);
          IOUtils.safeClose(outputStream);
        }

      }
    } else {
      throw new IOException("parameters has null value, from:" + src + ",to:" + dst);
    }
  }

  /**
   * Get All Files From Directory
   *
   * @param file
   * @param fileList
   */
  public static void getAllFiles(File file, List<File> fileList) {
    if (file.isDirectory()) {
      File[] files = file.listFiles();
      for (File childFile : files) {
        getAllFiles(childFile, fileList);
      }
    } else {
      fileList.add(file);
    }
  }

  /**
   * Read all content from file as a string
   *
   * @param file
   * @return
   */
  public static String getString(File file) {
    try {
      FileInputStream fis = new FileInputStream(file);
      final int size = fis.available();
      byte[] buffer = new byte[size];
      fis.read(buffer);
      fis.close();
      return new String(buffer, "utf-8");
    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return null;
  }

  public static boolean isSDCardReady(){
    return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
  }

  public static long getSDCardFreeSize(){
    if(!isSDCardReady()) return 0;
    final File sdCardDir = Environment.getExternalStorageDirectory();
    final StatFs sf = new StatFs(sdCardDir.getPath());
    final long blockSize = sf.getBlockSize();
    final long availCount = sf.getAvailableBlocks();

    return availCount * blockSize / 1024;
  }
}
